package com.amkai.aes.webservice.binary.objecthandler.ddm;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.StaleStateException;

import com.amkai.aes.generatedbeans.binarymgr.BinaryData;
import com.amkai.aes.generatedbeans.digitaldocumentmgr.BinaryContent;
import com.amkai.aes.generatedbeans.digitaldocumentmgr.Document;
import com.amkai.aes.generatedbeans.digitaldocumentmgr.DocumentComment;
import com.amkai.aes.generatedbeans.digitaldocumentmgr.ImageContent;
import com.amkai.aes.generatedbeans.digitaldocumentmgr.LinkInfo;
import com.amkai.aes.generatedbeans.digitaldocumentmgr.Page;
import com.amkai.aes.generatedbeans.digitaldocumentmgr.PageContent;
import com.amkai.aes.generatedbeans.digitaldocumentmgr.StoreInfo;
import com.amkai.aes.generatedbeans.insurance.InsurancePolicy;
import com.amkai.aes.generatedbeans.passport.Passport;
import com.amkai.aes.generatedbeans.personnel.details.PersonnelCommon;
import com.amkai.aes.generatedbeans.registration.Person;
import com.amkai.aes.generatedbeans.tasks.ManualTask;
import com.amkai.common.extensions.hibernate.config.SiteManager;
import com.amkai.common.extensions.hibernate.config.manager.SessionManager;
import com.amkai.rad.designerbase.beans.ChangedKind;

public class BinaryDataCleaner {
	private static final Log log = LogFactory.getLog(BinaryDataCleaner.class);
	private SessionManager sm;

	public BinaryDataCleaner() throws Exception {
		sm = SiteManager.Start();
		sm.openSession();
	}
	
	public BinaryDataCleaner(SessionManager sm) {
		this.sm = sm;
	}
	
	public void cleanUpBinary() throws Exception {
		cleanUpOldDocumnents();
		cleanUpReplacementsDocumnents();
		cleanUpUnassignedDocumnents();
		cleanUpDuplicates();
	}
	
	@SuppressWarnings("unchecked")
	public void cleanUpOldDocumnents() throws Exception {
		List<Document>docTBR = sm.execute("from Document as doc where doc.oldDocument = 1").list();
		for(Document doc : docTBR) {
			deleteDocument(doc,true);
		}
	}
	
	@SuppressWarnings("unchecked")
	public void cleanUpReplacementsDocumnents() throws Exception {
		List<Document>docTBR = sm.execute("from Document as doc where doc.oldDocument = 1 and doc.replacement = 1").list();
		for(Document doc : docTBR) {
			for(LinkInfo li : doc.getLinkInfo()) {
				li.setDocument(null);
				sm.saveRADInTransaction(li);
			}
			doc.getLinkInfo().clear();
			deleteDocument(doc,true);
		}
	}
	
	@SuppressWarnings("unchecked")
	public void cleanUpUnassignedDocumnents() throws Exception {
		List<Document>docTBR = sm.execute("from Document as doc where doc.oldDocument = 1 and doc.unassigned = 0").list();
		for(Document doc : docTBR) {
			for(LinkInfo li : doc.getLinkInfo()) {
				li.setDocument(null);
				sm.saveRADInTransaction(li);
			}
			doc.getLinkInfo().clear();
			deleteDocument(doc,true);
		}
	}
	
	@SuppressWarnings("unchecked")
	public void cleanUpDuplicates() throws Exception {
		
		String qs = "from BinaryData bf where exists (select bf2.id from BinaryData bf2 where bf2.id <> bf.id and bf2.storeName = bf.storeName)";
		List<BinaryData>bds = sm.execute(qs).list();
		List<BinaryData>bdTBR = new ArrayList<BinaryData>();
		List<ImageContent>icTBR = new ArrayList<ImageContent>();
		List<BinaryContent>bcTBR = new ArrayList<BinaryContent>();
		Set<Document>docTBR = new HashSet<Document>();
		
//		sm.clear();
		for(BinaryData bd : bds) {
//			bd = sm.get(BinaryData.class, bd.getId());
//			if(bd == null) continue;
			List<ImageContent>ics = sm.execute("from ImageContent as ic where ic.binaryData.id = "+bd.getId()).list();
			boolean keep = false;
			for(ImageContent ic : ics) {
				if(ic.getPage().size() > 0) {
					Page p = (Page) ic.getPage().toArray()[0];
					Document doc = p.getDocument();
					if(doc != null) {
						if(doc.getLinkInfo().size() > 0) {
							keep = true;
							continue;
						} else {
							docTBR.add(doc);
						}
					}
				} else {
					icTBR.add(ic);
				}
			}
			if(keep) continue;
			List<ImageContent>itcs = sm.execute("from ImageContent as ic where ic.thumbnailData.id = "+bd.getId()).list();
			for(ImageContent ic : itcs) {
				if(ic.getPage().size() > 0) {
					Page p = (Page) ic.getPage().toArray()[0];
					Document doc = p.getDocument();
					if(doc != null) {
						if(doc.getLinkInfo().size() > 0) {
							keep = true;
							continue;
						} else {
							docTBR.add(doc);
						}
					}
				} else {
					icTBR.add(ic);
				}
			}
			if(keep) continue;

			List<BinaryContent>bcs = sm.execute("from BinaryContent as bc where bc.binaryData.id = "+bd.getId()).list();
			for(BinaryContent bc : bcs) {
				if(bc.getPage().size() > 0) {
					Page p = (Page) bc.getPage().toArray()[0];
					Document doc = p.getDocument();
					if(doc != null) {
						if(doc.getLinkInfo().size() > 0) {
							keep = true;
							continue;
						} else {
							docTBR.add(doc);
						}
					}
				} else {
					bcTBR.add(bc);
				}
			}
			if(keep) continue;
			if(bd.getAvailableTaskXML().size() > 0) {
				continue;
			}
			if(sm.execute("from ReportDefinition rd where rd.rptBinaryData.id = "+bd.getId()).list().size() > 0) {
				continue;
			}
			bdTBR.add(bd);
		}
		log.info("========== DELETE BINARIES =======");
		
		for(Document doc : docTBR) {
			deleteDocument(doc, false);
		}
		
		for(ImageContent ic : icTBR) {
			deleteImageContent(ic, false);
		}
		
		for(BinaryContent bc : bcTBR) {
			deleteBinaryContent(bc, false);
		}
		
		for(BinaryData bd : bdTBR) {
			deleteBinaryData(bd);
		}
		
		log.info(bdTBR.size() + " BINARY DATA DELETED");
	}

	@SuppressWarnings("unchecked")
	private void deleteBinaryData(BinaryData bd) throws Exception {
		if(bd == null) return;
		if(bd.getChangedKind() == ChangedKind.DELETED) return;
		log.info("Binary will be deleted "+bd.getStoreName());
		Number nics = (Number)sm.execute("select count(*) from ImageContent as ic where ic.binaryData.id = "+bd.getId()).uniqueResult();
		Number nitcs = (Number)sm.execute("select count(*) from ImageContent as ic where ic.thumbnailData.id = "+bd.getId()).uniqueResult();
		Number nbcs = (Number)sm.execute("select count(*) from BinaryContent as bc where bc.binaryData.id = "+bd.getId()).uniqueResult();
		if (nics!=null && nics.intValue()>0) return;
		if (nitcs!=null && nitcs.intValue()>0) return;
		if (nbcs!=null && nbcs.intValue()>0) return;
//		List<ImageContent>ics = sm.execute("from ImageContent as ic where ic.binaryData.id = "+bd.getId()).list();
//		List<ImageContent>itcs = sm.execute("from ImageContent as ic where ic.thumbnailData.id = "+bd.getId()).list();
//		List<BinaryContent>bcs = sm.execute("from BinaryContent as bc where bc.binaryData.id = "+bd.getId()).list();
//		if(ics.size() > 0) return;
//		if(itcs.size() > 0) return;
//		if(bcs.size() > 0) return;
		sm.deleteRADInTransaction(bd);
		bd.setChangedKind(ChangedKind.DELETED);
		log.info("Binary DELETED "+bd.getStoreName());
	}

	private void deleteBinaryContent(BinaryContent bc, boolean keepBinary) throws Exception {
		log.info("Binary content will be deleted "+bc.getId());
		BinaryData bd = bc.getBinaryData();
		if(bc.getChangedKind() != ChangedKind.DELETED) {
			bd.getBinaryContent().remove(bc);
			sm.deleteRADInTransaction(bc);
			bc.setChangedKind(ChangedKind.DELETED);
		}
		if(keepBinary) return;
		deleteBinaryData(bd);
	}

	private void deleteImageContent(ImageContent ic, boolean keepBinary) throws Exception {
		log.info("Image content will be deleted "+ic.getId());
		BinaryData bd = ic.getBinaryData();
		BinaryData bdt = ic.getThumbnailData();
		if(ic.getChangedKind() != ChangedKind.DELETED) {
			bdt.getImageContent().remove(ic);
			bd.getImageContent().remove(ic);
			sm.deleteRADInTransaction(ic);
			ic.setChangedKind(ChangedKind.DELETED);
		}
		if(keepBinary) return;
		deleteBinaryData(bdt);
		deleteBinaryData(bd);
	}

	private void deletePage(Page p, boolean keepBinary) throws Exception {
		log.info("Page will be deleted "+p.getName());
		sm.evict(p);
		p = sm.get(Page.class, p.getId());
		if(p == null) return;
		PageContent pc = p.getPageContent();
		if(pc != null) {
			p.setPageContent(null);
			sm.saveRADInTransaction(p);
			if(pc instanceof ImageContent) {
				ImageContent ic = (ImageContent) pc;
				deleteImageContent(ic,keepBinary);
			} else {
				if(pc instanceof BinaryContent) {
					BinaryContent bc = (BinaryContent) pc;
					deleteBinaryContent(bc,keepBinary);
				} else {
					sm.deleteRADInTransaction(pc);
				}
			}
		}
		try {
			sm.deleteRADInTransaction(p);
		} catch(StaleStateException sse) {
			//this problem is occured in RH old db, do not know what does cause this
		}
	}

	private void deleteDocument(Document doc, boolean keepBinary) throws Exception {
		log.info("Document will be deleted "+doc.getName());
		sm.evict(doc);
		doc = sm.get(Document.class, doc.getId());
		if(doc == null) {
			log.warn("!!!! Document is already removed from the DB !!!!!");
			return;
		}
//		if(doc.getChangedKind() == ChangedKind.DELETED)
		for(LinkInfo li : doc.getLinkInfo()) {
			if(li.getCdmDischarge().size() > 0) return;
			if(li.getCdmHAP().size() > 0) return;
			if(li.getCdmPreAdmit().size() > 0) return;
			if(li.getCertification().size() > 0) return;
			if(li.getIndicator().size() > 0) return;
			if(li.getInsurancePolicy().size() > 0) return;
			if(li.getIpcvAuthorization().size() > 0) return;
			if(li.getIpcvPreVerification().size() > 0) return;
			if(li.getLicense().size() > 0) return;
			if(li.getOccurenceInformation().size() > 0) return;
			if(li.getOccurenceLog().size() > 0) return;
			if(li.getPathologyLog().size() > 0) return;
			if(li.getPersonDriverLicense().size() > 0) return;
			if(li.getPersonPersonPicture().size() > 0) return;
			if(li.getPersonSignature().size() > 0) return;
			if(li.getPhysStaffInsurancePolicy().size() > 0) return;
			if(li.getPrivilege().size() > 0) return;
			if(li.getReceiveOrder().size() > 0) return;
			if(li.getRemittancePostingSession().size() > 0) return;
			if(li.getReviewInformation().size() > 0) return;
			if(li.getSupplyLog().size() > 0) return;
			if(li.getSupplyResourceItem().size() > 0) return;
			if(li.getTask().size() > 0) return;
			
			sm.deleteRADInTransaction(li);
		}
		doc.setOldDocument(false);
		for(Page p : doc.getPages()) {
//			p.setDocument(null);
//			sm.saveRADInTransaction(p);
			deletePage(p,keepBinary);
		}

		for(DocumentComment dc : doc.getDocumentComments()) {
			sm.deleteRADInTransaction(dc);
		}
		
		for(StoreInfo si : doc.getStoreInfo()) {
			sm.deleteRADInTransaction(si);
		}
		
		for(InsurancePolicy ip : doc.getInsurancePolicy()) {
			ip.setInsuranceCard(null);
			sm.saveRADInTransaction(ip);
		}
		for(ManualTask mt : doc.getManualTask()) {
			mt.setDocument(null);
			sm.saveRADInTransaction(mt);
		}
		for(Person p : doc.getPerson()) {
			p.setDriverLicense(null);
			sm.saveRADInTransaction(p);
		}
		for(PersonnelCommon pc : doc.getPersonnelCommon()) {
			pc.setPicture(null);
			try {
				sm.saveRADInTransaction(pc);
			} catch(StaleStateException sse) {
				sse.printStackTrace();
				//RH DB problem
			}
		}
		
		try {
			sm.deleteRADInTransaction(doc);
		} catch(StaleStateException sse) {
			//RH DB problem
		}
	}
	
}
//select doc.name from Document as doc where doc.linkInfo.size = 0
//select bf.id, bf.storeName from BinaryData bf where exists (select bf2.id from BinaryData bf2 where bf2.id <> bf.id and bf2.storeName = bf.storeName) 
